package service

import (
	"fmt"
	"log"

	"time"

	"github.com/gomodule/redigo/redis"
	"github.com/juexin/gin-base/internal/config"
	"github.com/juexin/gin-base/pkg/utils"
	"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common"
	"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile"
	sms "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/sms/v20210111"
)

type SMSService struct {
	cfg            *config.Config
	redisPool      *redis.Pool
	smsClient      *sms.Client
	captchaService *CaptchaService
}

func NewSMSService(cfg *config.Config) *SMSService {
	// 初始化Redis连接池
	redisPool := &redis.Pool{
		MaxIdle:     cfg.Redis.MaxIdle,
		MaxActive:   cfg.Redis.MaxActive,
		IdleTimeout: time.Duration(cfg.Redis.IdleTimeout) * time.Second,
		Dial: func() (redis.Conn, error) {
			return redis.Dial("tcp", fmt.Sprintf("%s:%d", cfg.Redis.Host, cfg.Redis.Port),
				redis.DialPassword(cfg.Redis.Password),
				redis.DialDatabase(cfg.Redis.DB))
		},
	}

	// 初始化腾讯云短信客户端
	credential := common.NewCredential(cfg.SMS.SecretID, cfg.SMS.SecretKey)
	cpf := profile.NewClientProfile()
	cpf.HttpProfile.Endpoint = "sms.tencentcloudapi.com"

	smsClient, _ := sms.NewClient(credential, cfg.SMS.Region, cpf)

	return &SMSService{
		cfg:       cfg,
		redisPool: redisPool,
		smsClient: smsClient,
	}
}

func (s *SMSService) SetCaptchaService(captchaService *CaptchaService) {
	s.captchaService = captchaService
}

func (s *SMSService) GetRedisPool() *redis.Pool {
	return s.redisPool
}

// 请求结构体
type SMSRequest struct {
	Phone       string `json:"phone" binding:"required"`
	Purpose     string `json:"purpose" binding:"required"`
	CaptchaID   string `json:"captcha_id,omitempty"`
	CaptchaCode string `json:"captcha_code,omitempty"`
}

type VerifyCodeRequest struct {
	Phone   string `json:"phone" binding:"required"`
	Code    string `json:"code" binding:"required"`
	Purpose string `json:"purpose" binding:"required"`
}

// 响应结构体
type SMSResponse struct {
	Phone      string    `json:"phone"`
	Code       string    `json:"code,omitempty"`
	ExpireTime time.Time `json:"expire_time"`
	IsTest     bool      `json:"is_test"`
	RequestID  string    `json:"request_id"`
}

// SendVerificationCode 发送验证码
func (s *SMSService) SendVerificationCode(req *SMSRequest) (*SMSResponse, error) {
	conn := s.redisPool.Get()
	defer conn.Close()

	// 检查发送频率限制
	key := fmt.Sprintf("sms:rate:%s", req.Phone)
	exists, _ := redis.Bool(conn.Do("EXISTS", key))
	if exists {
		return nil, fmt.Errorf("发送太频繁，请稍后再试")
	}

	// 生成验证码
	code := utils.GenerateRandomCode(6)

	// 存储验证码
	codeKey := fmt.Sprintf("sms:code:%s:%s", req.Phone, req.Purpose)
	expireTime := time.Now().Add(time.Duration(s.cfg.SMS.ExpireMinutes) * time.Minute)

	_, err := conn.Do("SETEX", codeKey, s.cfg.SMS.ExpireMinutes*60, code)
	if err != nil {
		return nil, fmt.Errorf("存储验证码失败")
	}

	// 设置发送频率限制（1分钟内不能重复发送）
	conn.Do("SETEX", key, 60, "1")

	// 模拟发送短信（实际环境中应该调用真实的短信服务）
	isTest := s.cfg.SMS.SecretID == "dev-sms-secret-id"

	if !isTest {
		// 实际发送短信的代码
		log.Printf("发送短信验证码到 %s: %s", req.Phone, code)
	}

	return &SMSResponse{
		Phone:      req.Phone,
		Code:       code, // 测试环境返回验证码
		ExpireTime: expireTime,
		IsTest:     isTest,
		RequestID:  fmt.Sprintf("req_%d", time.Now().Unix()),
	}, nil
}

// VerifyCode 验证验证码
func (s *SMSService) VerifyCode(req *VerifyCodeRequest) error {
	conn := s.redisPool.Get()
	defer conn.Close()

	// 获取存储的验证码
	codeKey := fmt.Sprintf("sms:code:%s:%s", req.Phone, req.Purpose)
	storedCode, err := redis.String(conn.Do("GET", codeKey))
	if err != nil {
		if err == redis.ErrNil {
			return fmt.Errorf("验证码已过期或不存在")
		}
		return fmt.Errorf("获取验证码失败")
	}

	// 验证验证码
	if storedCode != req.Code {
		return fmt.Errorf("验证码错误")
	}

	// 验证成功，删除验证码
	conn.Do("DEL", codeKey)

	return nil
}

// GetRemainingAttempts 获取剩余尝试次数
func (s *SMSService) GetRemainingAttempts(phone, purpose string) (int, error) {
	conn := s.redisPool.Get()
	defer conn.Close()

	key := fmt.Sprintf("sms:attempts:%s:%s", phone, purpose)
	attempts, err := redis.Int(conn.Do("GET", key))
	if err != nil {
		if err == redis.ErrNil {
			return 5, nil // 默认5次尝试机会
		}
		return 0, err
	}

	return 5 - attempts, nil
}

// RecordFailedAttempt 记录失败尝试
func (s *SMSService) RecordFailedAttempt(phone, purpose string) {
	conn := s.redisPool.Get()
	defer conn.Close()

	key := fmt.Sprintf("sms:attempts:%s:%s", phone, purpose)
	conn.Do("INCR", key)
	conn.Do("EXPIRE", key, 24*60*60) // 24小时过期
}
